package com.vcc.boss.controller;


import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.idev.excel.ExcelWriter;
import cn.idev.excel.write.metadata.WriteSheet;
import com.mybatisflex.core.paginate.Page;
import com.vcc.core.derive.admin.DeriveWalletDetail;
import com.vcc.core.util.ExportUtil;
import com.vcc.core.annotations.RestPack;
import com.vcc.core.exception.ProgramException;
import com.vcc.core.util.RegexUtil;
import com.vcc.data.entity.BossUser;
import com.vcc.data.entity.Currency;
import com.vcc.data.entity.User;
import com.vcc.service.boss.response.walletDetail.WalletDetailVoBoss;
import com.vcc.service.service.BossUserService;
import com.vcc.service.service.CurrencyService;
import com.vcc.service.service.UserService;
import com.vcc.service.service.WalletDetailService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Optional;

@Log4j2
@RestController
@RequestMapping("walletDetail")
public class WalletDetailController {


    @Autowired
    private UserService userService;
    @Autowired
    private WalletDetailService walletDetailService;
    @Autowired
    private CurrencyService currencyService;
    @Autowired
    private BossUserService bossUserService;


    @RestPack
    @SaCheckPermission(value = "wallet:detail:list:view")
    @GetMapping("paging")
    public Page<WalletDetailVoBoss> paging(
            @RequestParam(value = "pageNumber", defaultValue = "1") Integer pageNumber,
            @RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize,
            Long targetUserId,
            Integer useFlag,
            String startDate,
            String endDate,
            String cardNumber,
            String remark,
            Long dealerId
    ) {
        Page<WalletDetailVoBoss> paging = walletDetailService.paging(Page.of(pageNumber, pageSize), targetUserId, cardNumber, useFlag, startDate, endDate, remark, dealerId);
        if (paging == null || paging.getRecords() == null || paging.getRecords().isEmpty()) {
            return new Page<>(pageNumber, pageSize);
        }
        List<Currency> list = currencyService.list();
        List<Long> userIds = paging.getRecords().stream()
                .map(WalletDetailVoBoss::getOperationUserId)
                .filter(id -> id != null && id != 0)
                .distinct()
                .toList();
        List<User> users = userIds.isEmpty() ? List.of() : userService.listByIds(userIds);
        List<BossUser> bossUsers = userIds.isEmpty() ? List.of() : bossUserService.listByIds(userIds);
        return paging.map(it -> {
            if (it.getOperationUserId() == null || it.getOperationUserId() == 0) {
                it.setOperationUserAccount(it.getAccount());
            } else {
                User userOptional = users.stream()
                        .filter(user -> user.getId().equals(it.getOperationUserId()))
                        .findAny()
                        .orElse(null);
                BossUser bossUserOptional = bossUsers.stream()
                        .filter(bossUser -> bossUser.getId().equals(it.getOperationUserId()))
                        .findAny()
                        .orElse(null);
                if (userOptional == null && bossUserOptional == null) {
                    it.setOperationUserAccount("");
                } else {
                    String account = Optional.ofNullable(userOptional).map(User::getAccount).orElse("");
                    String bossAccount = Optional.ofNullable(bossUserOptional).map(BossUser::getAccount).orElse("");
                    it.setOperationUserAccount(account.isEmpty() ? bossAccount : account);
                }
            }
            it.setCurrencyCode(list.stream()
                    .filter(cur -> cur.getId().equals(it.getCurrencyId()))
                    .findAny()
                    .map(Currency::getCode)
                    .orElse(""));
            return it;
        });
    }

    @GetMapping("derive")
    @SaCheckPermission(value = "wallet:detail:list:derive")
    public void derive(
            Long targetUserId,
            Integer useFlag,
            String startDate,
            String endDate,
            String cardNumber,
            String remark,
            Long dealerId,
            HttpServletResponse response
    ) {
        if (RegexUtil.checkStringIsNull(startDate)) {
            throw new ProgramException("请选择开始时间");
        }
        if (RegexUtil.checkStringIsNull(endDate)) {
            throw new ProgramException("请选择结束时间");
        }
        String fileName = System.currentTimeMillis() + "资金明细.xlsx";
        ExcelWriter excelWriter;
        try {
            ExportUtil.setExcelResponseHeaders(response, fileName);
            excelWriter = ExportUtil.createExcelWriter(response.getOutputStream(), DeriveWalletDetail.class);
        } catch (Exception e) {
            log.error("导出资金明细数据失败", e);
            throw new ProgramException("导出资金明细数据失败");
        }
        WriteSheet writeSheet = ExportUtil.createWriteSheet("资金明细", DeriveWalletDetail.class);
        Page<WalletDetailVoBoss> paging;
        Long pages = 1L;
        List<Currency> currencyList = currencyService.list();
        try {
            do {
                paging = walletDetailService.paging(Page.of(pages++, 500), targetUserId, cardNumber, useFlag, startDate, endDate, remark, dealerId);
                List<Long> userIds = paging.getRecords().stream()
                        .map(WalletDetailVoBoss::getOperationUserId)
                        .filter(id -> id != null && id != 0)
                        .distinct()
                        .toList();
                List<User> users = userIds.isEmpty() ? List.of() : userService.listByIds(userIds);
                List<BossUser> bossUsers = userIds.isEmpty() ? List.of() : bossUserService.listByIds(userIds);
                userIds = null;
                List<DeriveWalletDetail> list = paging.getRecords().stream().map(it -> {
                    if (it.getOperationUserId() == null || it.getOperationUserId() == 0) {
                        it.setOperationUserAccount(it.getAccount());
                    } else {
                        User userOptional = users.stream()
                                .filter(user -> user.getId().equals(it.getOperationUserId()))
                                .findAny()
                                .orElse(null);
                        BossUser bossUserOptional = bossUsers.stream()
                                .filter(bossUser -> bossUser.getId().equals(it.getOperationUserId()))
                                .findAny()
                                .orElse(null);
                        if (userOptional == null && bossUserOptional == null) {
                            it.setOperationUserAccount("");
                        } else {
                            String account = Optional.ofNullable(userOptional).map(User::getAccount).orElse("");
                            String bossAccount = Optional.ofNullable(bossUserOptional).map(BossUser::getAccount).orElse("");
                            it.setOperationUserAccount(account.isEmpty() ? bossAccount : account);
                        }
                    }
                    Currency currency = currencyList.stream().filter(cur -> cur.getId().equals(it.getCurrencyId())).findAny().orElse(null);
                    return DeriveWalletDetail.builder()
                            .id(it.getId())
                            .orderId(it.getOrderId())
                            .cardNumber(StringUtils.isBlank(it.getCardNumber()) ? "-" : it.getCardNumber())
                            .useFlag(it.getUseFlag())
                            .hasTransferIn(it.getHasTransferIn())
                            .userId(it.getUserId())
                            .userAccount(it.getAccount())
                            .amount(it.getAmount())
                            .currencyCode(currency == null ? "USD" : currency.getCode())
                            .balance(it.getWalletAmount())
                            .createTime(it.getRequestDate())
                            .remark(StringUtils.isBlank(it.getRemark()) ? "" : it.getRemark())
//                            .operationUserId(it.getOperationUserId() == null ? 0L : it.getOperationUserId())
                            .operationUserAccount(it.getOperationUserAccount())
                            .parentAccount("")
                            .dealerAccount(it.getDealerAccount())
                            .build();
                }).toList();
                ExportUtil.writeData(excelWriter, writeSheet, list);
                list = null;
                if (!bossUsers.isEmpty()){
                    bossUsers.clear();
                }
                if (!users.isEmpty()){
                    users.clear();
                }
            } while (!(pages).equals(paging.getTotalPage() + 1));
        } catch (Exception e) {
            log.error("导出Excel失败:", e);
            throw new ProgramException("导出Excel失败:" + e.getMessage());
        }
        ExportUtil.closeExcelWriter(excelWriter);
    }

}
